<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script>



    // 封装函数
    // 优点 -> 可以根据传入的参数快捷创建对象

    // 缺点:
    // 1. 通过函数创建的对象和函数没有关系(简单来说不是构造函数创建)
    // var arr = [1, 2, 3];  // new Array()
    // var obj = { a: 1, b: 2 };// new Object()

    // console.log(arr instanceof Array); // true
    // console.log(obj instanceof Object); // true

    // 2. 公有属性和方法重复创建 => 占内存



    function Cat(name, color) {
        // {}
        // this -> {}

        // 我们可以做的操作 把需要的属性和方法绑定到实例化对象上
        this.name = name;
        this.color = color;
        // this.specise = "Cat";
        // this.call = function () {
        //     console.log("喵喵");
        // }
        // this.skill = function () {
        //     console.log("捉老鼠");
        // }

        // return this;
    }

    // 问题: 公有的属性和方法还是重复 赋值到实例化对象中 占内存

    // 怎么解决?
    // 把实例化上公有的属性和方法提取出来, 统一放置(prototype原型对象) -> 允许所有的实例化对象访问

    // 提取之后 放在哪?
    // 1. 函数也是一个特殊的对象 (可以存储数据)
    // 2. 函数中存在原型对象(仅供构造函数使用) 函数.prototype = {constructor}  => 用于存储实例化对象公有的属性和方法(该构造函数创建的实例化对象)

    // console.dir(Cat);  // 以键值对象的形式打印对象(函数也是一个特殊的对象)
    // console.log(Cat.prototype); // {constructor}   //配置之前

    // 如何存储? => 原型对象也是一个对象数据 -> 点语法/中括号语法存储数据
    Cat.prototype.species = "Cat";
    Cat.prototype.call = function () {
        console.log("喵喵");
    }
    Cat.prototype.skill = function () {
        console.log("捉老鼠");
    }

    // 方法虽然存储在原型对象(公有的方法), 但是一般是由实例化对象来访问   this->指向调用此方法的实例化对象
    Cat.prototype.say = function () {
        // this->指向调用此方法的实例化对象 (哪个实例化对象调用它 他就指向谁)
        console.log("say方法被调用:", this);
        console.log(this.name, this.color);
    }

    // console.log(Cat.prototype); // {constructor,species,skill,call}


    // 如何使用原型对象上的属性和方法?  => 实例化对象上属性和方法的查找机制
    // 1. 先找实例化对象 =>  实例化对象自己有 就先找自己的
    // 2. 如果实例化对象上找不到, 就找构造函数的原型对象(公共的Cat.prototype)

    var Tom = new Cat("Tom", "black");
    console.log(Tom);

    // 1. 实例化对象自己有 就先找自己的(自己的)
    // console.log(Tom.name, Tom.color);

    // 2. 如果实例化对象上找不到, 就找构造函数的原型对象(公共的Cat.prototype)
    // console.log(Tom.species);
    // console.log(Tom.call);
    // console.log(Tom.skill);

    // Tom.call();
    // Tom.skill();

    Tom.say();  // 方法在调用时属于谁就指向谁  this -> Tom

    console.log("--------------------------------------------------");

    var Kitty = new Cat("Kitty", "pink");
    console.log(Kitty);

    Kitty.say(); // 方法在调用时属于谁就指向谁  this -> Tom





    // 总结:
    // 官方给每个构造函数提供了原型对象(prototype), 用于存放实例化对象上公有的属性和方法,供所有的实例化对象访问(前提: 该构造函数创建的实例化对象)








</script>

</html>